package com.mall.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson.JSONObject;
import com.mall.constant.PriceConstant;
import com.mall.dao.OrderMapper;
import com.mall.entity.*;
import com.mall.exception.NoStockException;
import com.mall.exception.OrderTokenException;
import com.mall.exception.PriceMismatchException;
import com.mall.service.OrderService;
import com.mall.constant.OrderConstant;
import com.mall.utils.UserCache;
import com.mall.vo.OrderStatusEnum;
import com.mall.vo.SettlementVo;
import com.mall.vo.SubmitOrderVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.locks.ReentrantLock;

@Service
@EnableAsync
public class OrderServiceImpl implements OrderService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private Snowflake snowflake;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    @Qualifier("taskExecutor")
    private Executor threadPoolExecutor;

    private ReentrantLock lock = new ReentrantLock();

    @Override
    public JSONObject settlement(SettlementVo settlementVo) {
        User user = UserCache.get();
        //防重令牌
        String orderToken = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + user.getId(), orderToken);
        //总金额
        BigDecimal totalAmount = settlementVo.getTotalAmount();
        //促销金额
        BigDecimal promotionAmount = new BigDecimal(PriceConstant.ZERO);
        //优惠卷抵扣
        BigDecimal couponAmount = new BigDecimal(PriceConstant.ZERO);
        //运费金额
        BigDecimal freightAmount = new BigDecimal(PriceConstant.ZERO);
        //应付金额
        BigDecimal payAmount = totalAmount
                .subtract(promotionAmount)
                .subtract(couponAmount)
                .subtract(freightAmount);

        JSONObject res = new JSONObject(new LinkedHashMap<>());
        res.put("cheakToken", orderToken);
        res.put("skuList", settlementVo.getSkuList());
        res.put("deliveryMethod", "包邮");
        res.put("totalAmount", totalAmount);
        res.put("promotionAmount", promotionAmount);
        res.put("couponAmount", couponAmount);
        res.put("freightAmount", freightAmount);
        res.put("payAmount", payAmount);
        res.put("skuNumCount", settlementVo.getSkuNumCount());
        return res;
    }

    @Transactional
    @Override
    public JSONObject submitOrder(SubmitOrderVo submitOrderVo) {
        User user = UserCache.get();
        //下单：创建订单、验令牌、验价格、锁库存
        //下单成功来到支付选项页
        //下单失败回到订单确认页重新确认订单信息
        lock.lock();
        //1.验证令牌
        try {
            String orderToken = submitOrderVo.getCheakToken();
            String redisToken = redisTemplate.opsForValue().get(OrderConstant.USER_ORDER_TOKEN_PREFIX + user.getId());
            if (orderToken == null || !Objects.equals(orderToken, redisToken)) {
                //验证失败
                throw new OrderTokenException("订单令牌失效");
            } else {
                //验证成功
                redisTemplate.delete(OrderConstant.USER_ORDER_TOKEN_PREFIX + user.getId());
                //1.创建订单(三层订单)
                String orderId = getOrderId();//生成订单id
                //创建一层单
                Order order1 = createOrder(submitOrderVo, user.getId(), 1, orderId, null);
                //验价
                BigDecimal payAmount = order1.getPayAmount();
                BigDecimal payPrice = submitOrderVo.getPayAmount();
                if (Math.abs(payAmount.subtract(payPrice).doubleValue()) < 0.01) {
                    //保存一层单
                    orderMapper.insert(order1);
                    //创建并保存二、三层单
                    List<SkuInfo> list = submitOrderVo.getSkuList();
                    ArrayList<String> skuNameList = new ArrayList<>();
                    if (!list.isEmpty()) {
                        for (SkuInfo skuInfo : list) {
                            skuNameList.add(skuInfo.getSkuName());
                            //创建二层单
                            Order order2 = createOrder(submitOrderVo, user.getId(), 2, orderId, skuInfo);
                            //保存二层单
                            orderMapper.insert(order2);
                            //创建三层单
                            Order order3 = createOrder(submitOrderVo, user.getId(), 3, orderId, skuInfo);
                            //保存三层单
                            orderMapper.insert(order3);
                        }
                    }
                    //库存锁定。只要有异常就回滚订单数据
                    orderLockStock(submitOrderVo);
                    JSONObject res = new JSONObject(new LinkedHashMap<>());
                    res.put("orderId", orderId);
                    res.put("receiveInfo", String.format("%s %s", order1.getName(), order1.getAddress()));
                    res.put("skuNameList", skuNameList);
                    res.put("invoiceInfo", "电子普通发票 个人");
                    res.put("payAmount", submitOrderVo.getPayAmount());
                    return res;
                } else {
                    throw new PriceMismatchException("订单验价失败");
                }
            }
        } finally {
            lock.unlock();
        }
    }


    //生成订单Id
    private String getOrderId() {
        return snowflake.nextIdStr();
    }

    //创建订单对象 1:一层单 2:二层单 3:三层单
    private Order createOrder(SubmitOrderVo submitOrderVo, Long userId, Integer orderType, String orderId, SkuInfo skuInfo) {
        Order order = new Order();
        if (orderType == 1) {
            /**
             * 一层单
             * 收货人信息、创建时间
             */
            Address address = submitOrderVo.getAddress();
            String summary = address.getSummary();
            String[] addrList = summary.split(",");
            order.setAddrProvince(addrList[0]);
            order.setAddrCity(addrList[1]);
            order.setAddrArea(addrList[2]);
            order.setAddrStreet(addrList[3]);
            summary = summary.replace(",", "");
            String addressDetail = address.getDetail();
            order.setAddress(summary + addressDetail);
            order.setName(address.getName());
            order.setMobile(address.getMobile());
            order.setUserId(userId);
            order.setOrderId(orderId);
            order.setOrderType(orderType);
            order.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
            //创建订单时间
            order.setCreateTime(new Timestamp(System.currentTimeMillis()));

            //计算应付金额
            BigDecimal payAmount = new BigDecimal(PriceConstant.ZERO);
            List<SkuInfo> skuList = submitOrderVo.getSkuList();
            for (SkuInfo sku : skuList) {
                BigDecimal subTotal = sku.getSubTotal();
                payAmount = payAmount.add(subTotal);
            }
            payAmount = payAmount
                    .subtract(submitOrderVo.getPromotionAmount())
                    .subtract(submitOrderVo.getCouponAmount())
                    .subtract(submitOrderVo.getFreightAmount());
            order.setPayAmount(payAmount);
            order.setTotalAmount(submitOrderVo.getTotalAmount());
            order.setPromotionAmount(submitOrderVo.getPromotionAmount());
            order.setCouponAmount(submitOrderVo.getCouponAmount());
            order.setFreightAmount(submitOrderVo.getFreightAmount());
            order.setSkuNumCount(submitOrderVo.getSkuNumCount());
        } else if (orderType == 2) {
            order.setOrderId(orderId);
            order.setOrderType(orderType);
            order.setSkuId(skuInfo.getSkuId());
        } else {
            order.setOrderId(orderId);
            order.setOrderType(orderType);
            order.setSkuId(skuInfo.getSkuId());
            order.setItemNum(skuInfo.getNum());
        }
        return order;
    }

    //锁定库存
    private Boolean orderLockStock(SubmitOrderVo submitOrderVo) {
        List<SkuInfo> skuList = submitOrderVo.getSkuList();
        boolean allStock = false;
        if (!skuList.isEmpty()) {
            for (SkuInfo skuInfo : skuList) {
                Long count = orderMapper.lockSkuStock(skuInfo.getNum(), skuInfo.getSkuId());
                if (count != 1) {
                    throw new NoStockException("库存不足");
                }
            }
            allStock = true;
        }
        return allStock;
    }


    //查询当前用户订单
    @Override
    public JSONObject queryOrderList(Integer userId) {
        /**
         * 全部订单
         */
        //查第一层
        List<Order> allOrders = orderMapper.selectByUserId(userId);
        //遍历获取每个订单，保存订单信息
        for (Order order : allOrders) {
            //查第二、三层
            String orderId = order.getOrderId();
            //用户购买的商品信息列表
            List<skuList> skuLists = orderMapper.selectByOrderId(orderId);
            //遍历获取每个商品，保存id、购买数量
            for (skuList sku : skuLists) {
                Integer skuId = sku.getSkuId();
                List<skuList> skuInfos = orderMapper.selectBySkuId(skuId);
                //遍历获取每个商品，保存名称、价格
                for (skuList skuInfo : skuInfos) {
                    sku.setSkuName(skuInfo.getSkuName());
                    sku.setPrice(skuInfo.getPrice());
                }
            }
            order.setSkuList(skuLists);
        }


        /**
         * 待支付订单
         */
        List<Order> toBePaid = new ArrayList<>();
        for (Order order : allOrders) {
            if (order.getStatus() == 0) {
                toBePaid.add(order);
            }
        }

        /**
         * 待发货订单
         */
        List<Order> toBeSend = new ArrayList<>();
        for (Order order : allOrders) {
            if (order.getStatus() == 1) {
                toBeSend.add(order);
            }
        }


        /**
         * 待收货订单
         */
        List<Order> toBeGet = new ArrayList<>();
        for (Order order : allOrders) {
            if (order.getStatus() == 2) {
                toBeGet.add(order);
            }
        }

        JSONObject res = new JSONObject(new LinkedHashMap<>());
        res.put("allOrders", allOrders);
        res.put("toBePaid", toBePaid);
        res.put("toBeSend", toBeSend);
        res.put("toBeGet", toBeGet);
        return res;


    }


    //修改订单的收货信息
    @Override
    public void updateAddress(String orderId, UpdateAddress updateAddress) {
        String name = updateAddress.getName();
        String mobile = updateAddress.getMobile();
        String summary = updateAddress.getSummary();
        String[] addrList = summary.split(",");
        String addrProvince = addrList[0];
        String addrCity = addrList[1];
        String addrArea = addrList[2];
        String addrStreet = addrList[3];
        String addrDetail = updateAddress.getDetail();
        orderMapper.updateAddress(orderId, name, mobile, addrProvince, addrCity, addrArea, addrStreet, addrDetail);
    }


    //修改订单的状态
    @Override
    public void updateStatus(String orderId, int status) {
        orderMapper.updateStatus(orderId, status);
    }


    //管理员根据订单编号查询全部订单
    @Override
    public List<TableData> queryAllOrder(String orderId, Integer currentPage, Integer pageSize) {
        //分页开始位置
        Integer start = (currentPage - 1) * pageSize;
        List<TableData> tableData = orderMapper.queryAllOrder(orderId, start, pageSize);
        return tableData;
    }

    //查询订单总条数
    @Override
    public Long queryCount(String orderId) {
        Long total = orderMapper.queryCount(orderId);
        return total;
    }

    //管理员根据订单编号删除订单
    @Override
    public void deleteOrder(String orderId) {
        orderMapper.deleteOrder(orderId);
    }

    //管理员根据订单编号查询订单
    @Override
    public TableData queryOrder(String orderId) {
        TableData currentEditOrder = orderMapper.queryOrder(orderId);
        return currentEditOrder;
    }

    //管理员根据订单编号修改订单
    @Override
    public void updateOrder(String orderId, Integer status, String createTime) {
        orderMapper.updateOrder(orderId, status, createTime);
    }

    //根据订单编号查询用户id
    @Override
    public Integer queryUserId(String orderId) {
        Integer userId = orderMapper.queryUserId(orderId);
        return userId;
    }

}